using System;
using System.Collections.Generic;
using SilenthinkContract.Component;

namespace SilenthinkContract.Util
{
    public sealed class TreeFactory<T>where T:ITreeNodeCategory
    {
        private readonly Func<ITreeNodeCategory, ITreeNodeCategory, TreeNodeCompareResult> compare;
        public TreeFactory()
        {
            compare = CategoryCompare;
        }
        public TreeFactory(Func<ITreeNodeCategory, ITreeNodeCategory, TreeNodeCompareResult> compare)
        {
            this.compare = compare;
        }
        public List<TreeNode<T>> CreateTreeByLevel(List<T> items)
        {
            items.Sort(CompareResult);
            var result = new List<TreeNode<T>>();
            TreeNode<T> lastNode = null;
            var queue = new Queue<TreeNode<T>>();
            TreeNode<T> currentNode = null;
            var current = result;
            if (items.Count > 0)
            {
                foreach (var t in items)
                {
                    var addedNode = new TreeNode<T>
                    {
                        Data = t,
                        Parent = null,
                        Children = new List<TreeNode<T>>()
                    };//生成要添加的数据 

                    queue.Enqueue(addedNode);//入队
                    //看是否到了下一层的结点
                    if (lastNode != null &&
                        (compare(addedNode.Data, lastNode.Data) == TreeNodeCompareResult.Child
                         || compare(addedNode.Data, lastNode.Data) == TreeNodeCompareResult.NexLevelNode)//下一层：即结点是子结点或是下一层结点
                        )
                    {
                        currentNode = queue.Dequeue();

                    }
                    //找到对应的父结点
                    while (currentNode != null && compare(addedNode.Data, currentNode.Data) != TreeNodeCompareResult.Child)
                    {
                        currentNode = queue.Dequeue();
                    }
                    if (currentNode != null && compare(addedNode.Data, currentNode.Data) != TreeNodeCompareResult.EquealNode)
                    {
                        addedNode.Parent = currentNode;
                        current = currentNode.Children;
                    }
                    current.Add(addedNode);
                    lastNode = addedNode;
                }
            }
            return result;
        }
        private int CompareResult(T x, T y)
        {
            switch (compare(x, y))
            {
                case TreeNodeCompareResult.Child:
                case TreeNodeCompareResult.NextNode:
                case TreeNodeCompareResult.NexLevelNode:
                    return 1;
                case TreeNodeCompareResult.Parent:
                case TreeNodeCompareResult.PreNode:
                    return -1;
                default:
                    return 0;
            }
        }
        private static TreeNodeCompareResult CategoryCompare(ITreeNodeCategory x, ITreeNodeCategory y)
        {
            if (x.Code == y.Code)
            {
                return TreeNodeCompareResult.EquealNode;
            }
            if (x.Code.Length > y.Code.Length)
            {
                return x.Code.IndexOf(y.Code) == 0 ? TreeNodeCompareResult.Child : TreeNodeCompareResult.NexLevelNode;
            }
            if (x.Code.Length < y.Code.Length)
            {
                return TreeNodeCompareResult.Parent;
            }
            return x.Code.CompareTo(y.Code) < 0 ? TreeNodeCompareResult.PreNode : TreeNodeCompareResult.NextNode;
        }

    }
}